package com.wfs.myapp.service.impl;

import com.wfs.myapp.common.ApiResult;
import com.wfs.myapp.common.Constant;
import com.wfs.myapp.entity.domain.User;
import com.wfs.myapp.entity.domain.bk.BkBook;
import com.wfs.myapp.entity.domain.bk.BkOrder;
import com.wfs.myapp.entity.domain.bk.BkSendMessage;
import com.wfs.myapp.entity.dto.req.bk.ApproveReqDto;
import com.wfs.myapp.entity.dto.req.bk.BorrowReqDto;
import com.wfs.myapp.entity.vo.OrderVo;
import com.wfs.myapp.entity.vo.PageResponse;
import com.wfs.myapp.enums.*;
import com.wfs.myapp.repository.UserRepository;
import com.wfs.myapp.repository.bk.BookRepository;
import com.wfs.myapp.repository.bk.OrderRepository;
import com.wfs.myapp.repository.bk.SendMessageRepository;
import com.wfs.myapp.service.BkOrderService;
import com.wfs.myapp.utils.DateUtils;
import com.wfs.myapp.utils.SqeUtil;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;

@Service
public class BkOrderServiceImpl implements BkOrderService {

    @Autowired
    private OrderRepository orderRepository;

    @Autowired
    private UserRepository userRepository;

    @Autowired
    private BookRepository bookRepository;

    @Autowired
    private SendMessageRepository sendMessageRepository;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public ApiResult<?> borrow(Long userId, BorrowReqDto borrowReqDto) {
        // check
        Optional<BkBook> byId = bookRepository.findById(borrowReqDto.getBookId());
        if (!byId.isPresent()) return ApiResult.error(ResponseCodeEnum.BOOK_NOT_EXIST);
        BkBook book = byId.get();
        Optional<User> byId1 = userRepository.findById(book.getUserId());
        if (!byId1.isPresent()) return ApiResult.error(ResponseCodeEnum.USER_NOT_EXIST);
        if (book.getStatus().equals(BookStatusEnum.APPROVE.getCode())) return ApiResult.error(ResponseCodeEnum.BOOK_BORROWED);
        List<BkOrder> byBookId = orderRepository.findByBookId(borrowReqDto.getBookId()).stream().filter(dbOrder -> dbOrder.getStatus().equals(OrderStatusEnum.APPROVE.getCode()) || dbOrder.getStatus().equals(OrderStatusEnum.EXCEEDING.getCode()) || dbOrder.getStatus().equals(OrderStatusEnum.RETURN.getCode())).collect(Collectors.toList());
        if (!CollectionUtils.isEmpty(byBookId)) return ApiResult.error(ResponseCodeEnum.ORDER_ERROR);
        if(userId.equals(book.getUserId())) return ApiResult.error(ResponseCodeEnum.BORROW_INVALID);
        List<OrderVo> borrowingList = orderRepository.findByMasterUserIdAndStatus(OrderDirectionEnum.INPUT.getCode(), userId, Arrays.asList(OrderStatusEnum.BORROWING.getCode()), 0, 1);
        if (!CollectionUtils.isEmpty(borrowingList)) return ApiResult.error(ResponseCodeEnum.ORDER_EXIST);

        BkOrder order = new BkOrder();
        order.setOrderId(SqeUtil.getOrderSeq(Constant.BK_ORDER_PRE));
        order.setBorrowUserId(userId);
        order.setMasterUserId(book.getUserId());
        order.setBookId(borrowReqDto.getBookId());
        order.setDeadline(DateUtils.stringToDate(borrowReqDto.getDeadline(), DateUtils.YMD));
        order.setStatus(OrderStatusEnum.BORROWING.getCode());
        order.setCreatedBy(String.valueOf(userId));
        order.setUpdatedBy(String.valueOf(userId));
        // book status
        BkOrder save = orderRepository.save(order);
        book.setStatus(BookStatusEnum.BORROWING.getCode());
        bookRepository.save(book);
        // send message
        BkSendMessage bkSendMessage = new BkSendMessage();
        bkSendMessage.setType(SearchTypeEnum.ORDER.getCode());
        bkSendMessage.setTargetId(save.getId());
        bkSendMessage.setStatus(MessageStatusEnum.UN_SEND.getCode());
        bkSendMessage.setCreatedBy(String.valueOf(userId));
        bkSendMessage.setUpdatedBy(String.valueOf(userId));
        sendMessageRepository.save(bkSendMessage);
        return ApiResult.success(save);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public ApiResult<?> borrowProcess(Long userId, ApproveReqDto approveReqDto) {
        Optional<BkOrder> orderOpt = orderRepository.findById(approveReqDto.getId());
        if (!orderOpt.isPresent()) return ApiResult.error(ResponseCodeEnum.ORDER_NOT_EXIST);
        BkOrder order = orderOpt.get();
        order.setStatus(approveReqDto.getStatus());
        order.setUpdatedTime(LocalDateTime.now());
        order.setUpdatedBy(String.valueOf(userId));
        orderRepository.save(order);
        OrderVo vo = new OrderVo();
        BeanUtils.copyProperties(order, vo);
        vo.setStatusStr(OrderStatusEnum.getMsg(order.getStatus()));
        Optional<BkBook> bookOpt = bookRepository.findById(order.getBookId());
        if (!bookOpt.isPresent()) return ApiResult.error(ResponseCodeEnum.BOOK_NOT_EXIST);
        BkBook book = bookOpt.get();
        book.setStatus(BookStatusEnum.BORROWING.getCode());
        bookRepository.save(book);
        if (approveReqDto.getStatus().equals(OrderStatusEnum.DONE.getCode())) {
            BkSendMessage bkSendMessage = sendMessageRepository.findByTypeAndTargetId(SearchTypeEnum.ORDER.getCode(), order.getId());
            bkSendMessage.setStatus(MessageStatusEnum.CANCEL.getCode());
            sendMessageRepository.save(bkSendMessage);
        }
        return ApiResult.success(vo);
    }

    @Override
    public ApiResult<?> myOrderList(Long userId, Integer orderDirection, List<Integer> statusList, Integer page, Integer size) {
        List<OrderVo> orderList = new ArrayList<>();
        long total;
        if (OrderDirectionEnum.INPUT.getCode().equals(orderDirection)) {
            // 借入
            total = orderRepository.countByMasterUserIdAndStatus(orderDirection, userId, statusList);
            if (total == 0) return ApiResult.success(new PageResponse(new ArrayList(), total, page, size));
            orderList = orderRepository.findByMasterUserIdAndStatus(orderDirection, userId, statusList, (page-1)*size, size);
            orderList.forEach(orderVo -> orderVo.setStatusStr(OrderStatusEnum.getMsg(orderVo.getStatus())));
            return ApiResult.success(new PageResponse(orderList, total, page, size));
        } else {
            // 借出
            total = orderRepository.countByMasterUserIdAndStatus(orderDirection, userId, statusList);
            if (total == 0) return ApiResult.success(new PageResponse(new ArrayList(), total, page, size));
            orderList = orderRepository.findByMasterUserIdAndStatus(orderDirection, userId, statusList, (page-1)*size, size);
            orderList.forEach(orderVo -> orderVo.setStatusStr(OrderStatusEnum.getMsg(orderVo.getStatus())));
        }
        return ApiResult.success(new PageResponse(orderList, total, page, size));

    }


}












